package com.dragon.common.modules.uaa.service.assistants;

import com.dragon.common.modules.uaa.common.assistants.JwtAssist;
import com.dragon.common.modules.uaa.dao.repository.UaaAccountRoleRepository;
import com.dragon.common.modules.uaa.dao.repository.UaaAuthorityRepository;
import com.dragon.common.modules.uaa.dao.repository.UaaRoleAuthorityRepository;
import com.dragon.common.modules.uaa.domain.entity.UaaAccountEntity;
import com.dragon.common.modules.uaa.service.assistants.def.LoginAssistant;
import com.dragon.common.modules.uaa.web.models.results.LoginResult;
import com.dragon.common.spring.annotations.Assistant;
import com.dragon.common.modules.uaa.domain.entity.UaaAccountRoleEntity;
import com.dragon.common.modules.uaa.domain.entity.UaaAuthorityEntity;
import com.dragon.common.modules.uaa.domain.entity.UaaRoleAuthorityEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author Chris Chan
 * Create On 2025/8/8 下午3:13
 * Use for:
 * Explain:
 */
@Assistant
public class LoginAssistantImpl implements LoginAssistant {
    private PasswordEncoder passwordEncoder;
    private JwtAssist jwtAssist;
    private UaaRoleAuthorityRepository uaaRoleAuthorityRepository;
    private UaaAuthorityRepository uaaAuthorityRepository;
    private UaaAccountRoleRepository uaaAccountRoleRepository;

    @Autowired
    public LoginAssistantImpl(PasswordEncoder passwordEncoder,
                              JwtAssist jwtAssist,
                              UaaRoleAuthorityRepository uaaRoleAuthorityRepository,
                              UaaAuthorityRepository uaaAuthorityRepository,
                              UaaAccountRoleRepository uaaAccountRoleRepository) {
        this.passwordEncoder = passwordEncoder;
        this.jwtAssist = jwtAssist;
        this.uaaRoleAuthorityRepository = uaaRoleAuthorityRepository;
        this.uaaAuthorityRepository = uaaAuthorityRepository;
        this.uaaAccountRoleRepository = uaaAccountRoleRepository;
    }

    /**
     * 检查密码
     *
     * @param password 密码
     * @return 是否正确
     */
    public boolean checkPassword(UaaAccountEntity account, String password) {
        return matches(password, account.getPassword());
    }

    /**
     * 检查密码
     *
     * @param password        密码
     * @param encodedPassword 编码后的密码
     * @return 是否正确
     */
    @Override
    public boolean matches(String password, String encodedPassword) {
        return passwordEncoder.matches(password, encodedPassword);
    }

    /**
     * 构建登录结果
     *
     * @param userCode
     * @param username
     * @return
     */
    @Override
    public LoginResult buildLoginResult(Long userCode, String username) {

        // 生成令牌
        String accessToken = jwtAssist.generateAccessToken(
                userCode,
                username,
                getAuthorities(userCode)
        );
        String refreshToken = jwtAssist.generateRefreshToken(
                userCode,
                username
        );
        return new LoginResult(
                accessToken,
                jwtAssist.getAccessTokenExpiration(),
                refreshToken,
                jwtAssist.getRefreshTokenExpiration()
        );
    }


    /**
     * 获取权限
     *
     * @param userCode
     * @return
     */
    @Override
    public List<String> getAuthorities(long userCode) {
        // 获取权限
        return Optional.ofNullable(uaaAccountRoleRepository.findByAccountCode(userCode))
                .map(accountRoles -> accountRoles.stream().map(UaaAccountRoleEntity::getRoleCode).toList())
                .map(roleCodes -> uaaRoleAuthorityRepository.findByRoleCodeIn(roleCodes))
                .map(roleAuthorities -> roleAuthorities.stream().map(UaaRoleAuthorityEntity::getAuthorityCode).toList())
                .map(authorityCodes -> uaaAuthorityRepository.findByCodeIn(authorityCodes))
                .map(authorities -> authorities.stream().map(UaaAuthorityEntity::getName).collect(Collectors.toSet()))
                .map(authorityNames -> authorityNames.stream().toList())
                .orElseGet(List::of);

    }

    /**
     * 从刷新令牌中获取用户编码
     *
     * @param refreshToken 刷新令牌
     * @return 用户编码
     */
    @Override
    public boolean validateToken(String refreshToken) {
        // 校验刷新令牌
        return jwtAssist.validateToken(refreshToken);

        //todo: 从缓存中查找令牌,要考虑过期的问题
    }
}
